Imports System.Drawing
Namespace UI.Windows
  ''' <summary>
  ''' Controls how control validates input.
  ''' </summary>
  ''' <remarks></remarks>
  Public Enum Validate
    ''' <summary>
    ''' Turns off validation.
    ''' </summary>
    ''' <remarks></remarks>
    None
    ''' <summary>
    ''' Validates credit card number.
    ''' </summary>
    ''' <remarks></remarks>
    CreditCard
    ''' <summary>
    ''' Custom validation.
    ''' </summary>
    ''' <remarks></remarks>
    Custom
    ''' <summary>
    ''' Validates date.
    ''' </summary>
    ''' <remarks></remarks>
    [Date]
    ''' <summary>
    ''' Validates domain address.
    ''' </summary>
    ''' <remarks></remarks>
    Domain
    ''' <summary>
    ''' Validates email address.
    ''' </summary>
    ''' <remarks></remarks>
    Email
    ''' <summary>
    ''' Validates file path.
    ''' </summary>
    ''' <remarks></remarks>
    FilePath
    ''' <summary>
    ''' Validates first and last name.
    ''' </summary>
    ''' <remarks></remarks>
    FirstLastName
    ''' <summary>
    ''' Validates ISBN number.
    ''' </summary>
    ''' <remarks></remarks>
    Isbn
    ''' <summary>
    ''' Validates number.
    ''' </summary>
    ''' <remarks></remarks>
    Number
    ''' <summary>
    ''' Validates US phone number.
    ''' </summary>
    ''' <remarks></remarks>
    Phone
    ''' <summary>
    ''' Validates scientific number.
    ''' </summary>
    ''' <remarks></remarks>
    Scientific
    ''' <summary>
    ''' Validates US Social Security number.
    ''' </summary>
    ''' <remarks></remarks>
    SocialSecurity
    ''' <summary>
    ''' Validates a string.
    ''' </summary>
    ''' <remarks></remarks>
    [String]
    ''' <summary>
    ''' Validates a temperature.
    ''' </summary>
    ''' <remarks></remarks>
    Temperature
    ''' <summary>
    ''' Validates a URL address.
    ''' </summary>
    ''' <remarks></remarks>
    Url
    ''' <summary>
    ''' Validates a US zip code.
    ''' </summary>
    ''' <remarks></remarks>
    ZipCode
  End Enum

  ''' <summary>
  ''' Modified TexBox control
  ''' </summary>
  Public Class TextBox
    Inherits System.Windows.Forms.TextBox

    Private _autoSelect As Boolean
    Private _autoValidate As Validate = Validate.None
    Private _backColor As Color = MyBase.BackColor
    Private _invalidBackColor As Color = Color.LightPink
    Private _readOnlyBackColor As Color = System.Drawing.SystemColors.Control
    Private _customRegEx As String = String.Empty

    ''' <summary>
    ''' Auto selects text when control receives focus.
    ''' </summary>
    ''' <value>Selects text if set to <see cref="Boolean">true</see>.</value>
    ''' <returns>Selects text if set to <see cref="Boolean">true</see>.</returns>
    ''' <remarks></remarks>
    <ComponentModel.Category("Behavior"), ComponentModel.DefaultValue(False), ComponentModel.Description("Automatically selects text when control receives focus.")> _
    Public Property AutoSelect() As Boolean
      Get
        Return Me._autoSelect
      End Get
      Set(ByVal value As Boolean)
        Me._autoSelect = value
      End Set
    End Property

    ''' <summary>
    ''' Auto validates input as user types into the TextBox.
    ''' </summary>
    ''' <value>Use <see cref="Validate">Validate</see>to configure how control validates input.</value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    <ComponentModel.Category("Behavior"), ComponentModel.Description("Automatically validates value typed into the TextBox.")> _
    Public Property AutoValidate() As Validate
      Get
        Return Me._autoValidate
      End Get
      Set(ByVal value As Validate)
        Me._autoValidate = value
      End Set
    End Property

    ''' <summary>
    ''' Sets background color of control if input is invalid.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    <ComponentModel.Category("Appearance"), ComponentModel.Description("Backgroung color if value of TextBox is invalid.")> _
    Public Property InvalidBackColor() As Color
      Get
        Return Me._invalidBackColor
      End Get
      Set(ByVal value As Color)
        Me._invalidBackColor = value
      End Set
    End Property

    ''' <summary>
    ''' Sets background color of control if set to read-only.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    <ComponentModel.Category("Appearance"), ComponentModel.Description("Backgroung color if TextBox is read only.")> _
    Public Property ReadOnlyBackColor() As Color
      Get
        Return Me._readOnlyBackColor
      End Get
      Set(ByVal value As Color)
        Me._readOnlyBackColor = value
      End Set
    End Property

    ''' <summary>
    ''' Used to set regular expression of validation is set to custom.
    ''' </summary>
    ''' <value>Regular expression as <see cref="String"></see></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    <ComponentModel.Category("Behavior"), ComponentModel.Description("Custom regular expression for validating text.")> _
    Public Property CustomValidationExpression() As String
      Get
        Return Me._customRegEx
      End Get
      Set(ByVal value As String)
        Me._customRegEx = value
      End Set
    End Property

    Public Overrides Property BackColor() As System.Drawing.Color
      Get
        If Me.ReadOnly Then
          Return Me.ReadOnlyBackColor
        Else
          Return MyBase.BackColor
        End If
      End Get
      Set(ByVal value As Color)
        MyBase.BackColor = value
      End Set
    End Property

    Private Sub TextBox_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.GotFocus
      If Me.AutoSelect Then
        Me.SelectControlText()
      End If
    End Sub

    Private Sub SelectControlText()

      If Me.Text.Length > 0 Then
        Me.Select(0, Me.Text.Length)
      End If

    End Sub

    Private Sub TextBox_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.TextChanged

      Me.ValidateInput()

    End Sub

    Private Sub ValidateInput()
      Dim backColor As Color = Me._backColor

      If Not Me.ReadOnly AndAlso Me.AutoValidate <> Validate.None Then
        If Not Me.IsValidText(Me.Text) Then
          backColor = Me.InvalidBackColor
        End If
      End If

      If Me.BackColor <> backColor Then
        Me.BackColor = backColor
      End If

    End Sub

    ''' <summary>
    ''' Determins if user input is valid.
    ''' </summary>
    ''' <param name="text">Input as <see cref="String"></see></param>
    ''' <returns>True if valid.</returns>
    ''' <remarks></remarks>
    Protected Overridable Function IsValidText(ByVal text As String) As Boolean

      If Not [Enum].IsDefined(GetType(Validate), Me.AutoValidate) Then
        Throw New InvalidOperationException("AutoValidate value is not valid!")
      End If

      Dim valid As Boolean

      If Not String.IsNullOrEmpty(text) Then

        Select Case Me.AutoValidate
          Case Is = Validate.CreditCard
            valid = ValidationHelper.IsValidCreditCard(text)
          Case Is = Validate.Custom
            valid = ValidationHelper.IsValidString(text, Me.CustomValidationExpression)
          Case Is = Validate.Date
            valid = ValidationHelper.IsValidDate(text)
          Case Is = Validate.Domain
            valid = ValidationHelper.IsValidDomain(text)
          Case Is = Validate.Email
            valid = ValidationHelper.IsValidEmail(text)
          Case Is = Validate.FilePath
            valid = ValidationHelper.IsValidFilePath(text)
          Case Is = Validate.FirstLastName
            valid = ValidationHelper.IsValidFirstLastName(text)
          Case Is = Validate.Isbn
            valid = ValidationHelper.IsValidIsbn(text)
          Case Is = Validate.Number
            valid = ValidationHelper.IsValidNumber(text)
          Case Is = Validate.Phone
            valid = ValidationHelper.IsValidPhone(text)
          Case Is = Validate.Scientific
            valid = ValidationHelper.IsValidScientific(text)
          Case Is = Validate.SocialSecurity
            valid = ValidationHelper.IsValidSocialSecurity(text)
          Case Is = Validate.String
            valid = ValidationHelper.IsValidString(text)
          Case Is = Validate.Temperature
            valid = ValidationHelper.IsValidString(text)
          Case Is = Validate.Url
            valid = ValidationHelper.IsValidUrl(text)
          Case Is = Validate.ZipCode
            valid = ValidationHelper.IsValidPostalCode(text)
        End Select

      End If

      Return valid

    End Function

  End Class
End Namespace
